'''
源头：https://www.cnblogs.com/yyds/p/6901864.html
logging模块简介
    1. logging模块的日志级别
        日志等级（level）| 描述
            | -
            DEBUG | 最详细的日志信息，典型应用场景是 问题诊断
            INFO | 信息详细程度仅次于DEBUG，通常只记录关键节点信息，用于确认一切都是按照我们预期的那样进行工作
            WARNING | 当某些不期望的事情发生时记录的信息（如，磁盘可用空间较低），但是此时应用程序还是正常运行的
            ERROR | 由于一个更严重的问题导致某些功能不能正常运行时记录的信息
            CRITICAL | 当发生严重错误，导致应用程序不能继续运行时记录的信息
        说明：
            上面列表中的日志等级是从上到下依次升高的，即：DEBUG < INFO < WARNING < ERROR < CRITICAL，而日志的信息量是依次减少的；
            当为某个应用程序指定一个日志级别后，应用程序会记录所有日志级别大于或等于指定日志级别的日志信息，而不是仅仅记录指定级别的日志信息，
            nginx、php等应用程序以及这里要提高的python的logging模块都是这样的。同样，logging模块也可以指定日志记录器的日志级别，
            只有级别大于或等于该指定日志级别的日志记录才会被输出，小于该等级的日志记录将会被丢弃。
    2. logging模块的使用方式介绍
        logging模块提供了两种记录日志的方式：
            第一种方式是使用logging提供的模块级别的函数
            第二种方式是使用Logging日志系统的四大组件
            其实，logging所提供的模块级别的日志记录函数也是对logging日志系统相关类的封装而已。
        logging模块定义的模块级别的常用函数
            函数 | 说明
                | -
                logging.debug(msg, *args, **kwargs) | 创建一条严重级别为DEBUG的日志记录
                logging.info(msg, *args, **kwargs) | 创建一条严重级别为INFO的日志记录
                logging.warning(msg, *args, **kwargs) | 创建一条严重级别为WARNING的日志记录
                logging.error(msg, *args, **kwargs) | 创建一条严重级别为ERROR的日志记录
                logging.critical(msg, *args, **kwargs) | 创建一条严重级别为CRITICAL的日志记录
                logging.log(level, *args, kwargs) | 创建一条严重级别为level的日志记录
                logging.basicConfig(kwargs) | 对root logger进行一次性配置
                其中logging.basicConfig(**kwargs)函数用于指定“要记录的日志级别”、“日志格式”、“日志输出位置”、“日志文件的打开模式”等信息，
                    其他几个都是用于记录各个级别日志的函数。
        logging模块的四大组件
            组件 | 说明
                | -
                loggers | 提供应用程序代码直接使用的接口
                handlers | 用于将日志记录发送到指定的目的位置
                filters | 提供更细粒度的日志过滤功能，用于决定哪些日志记录将会被输出（其它的日志记录将会被忽略）
                formatters | 用于控制日志信息的最终输出格式
                说明： logging模块提供的模块级别的那些函数实际上也是通过这几个组件的相关实现类来记录日志的，只是在创建这些类的实例时设置了一些默认值。
'''
# import logging

'''
logging.debug("This is a debug log.")
logging.info("This is a info log.")
logging.warning("This is a warning log.")
logging.error("This is a error log.")
logging.critical("This is a critical log.")

输出结果：
    WARNING:root:This is a warning log.
    ERROR:root:This is a error log.
    CRITICAL:root:This is a critical log.
问题1：为什么前面两条日志没有被打印出来？
    这是因为logging模块提供的日志记录函数所使用的日志器设置的日志级别是WARNING，因此只有WARNING级别的日志记录以及大于它的ERROR和CRITICAL级别的日志记录被输出了，而小于它的DEBUG和INFO级别的日志记录被丢弃了。
问题2：打印出来的日志信息中各字段表示什么意思？为什么会这样输出？
    上面输出结果中每行日志记录的各个字段含义分别是：日志级别:日志器名称:日志内容
    之所以会这样输出，是因为logging模块提供的日志记录函数所使用的日志器设置的日志格式默认是BASIC_FORMAT，其值为："%(levelname)s:%(name)s:%(message)s"
问题3：如何将日志记录输出到文件中，而不是打印到控制台？
    因为在logging模块提供的日志记录函数所使用的日志器设置的处理器所指定的日志输出位置默认为:sys.stderr。
问题4：怎么修改这些默认设置呢？
    在我们调用上面这些日志记录函数之前，手动调用一下basicConfig()方法，把我们想设置的内容以参数的形式传递进去就可以了。

logging.basicConfig()函数说明
    该方法用于为logging日志系统做一些基本配置，方法定义如下：logging.basicConfig(**kwargs)
    该函数可接收的关键字参数如下：
        参数名称 | 描述
                | -
                filename | 指定日志输出目标文件的文件名，指定该设置项后日志信心就不会被输出到控制台了
                filemode | 指定日志文件的打开模式，默认为'a'。需要注意的是，该选项要在filename指定时才有效
                format | 指定日志格式字符串，即指定日志输出时所包含的字段信息以及它们的顺序。logging模块定义的格式字段下面会列出。
                datefmt | 指定日期/时间格式。需要注意的是，该选项要在format中包含时间字段%(asctime)s时才有效
                level | 指定日志器的日志级别
                stream | 指定日志输出目标stream，如sys.stdout、sys.stderr以及网络stream。需要说明的是，stream和filename不能同时提供，否则会引发 ValueError异常
                style | Python 3.2中新添加的配置项。指定format格式字符串的风格，可取值为'%'、'{'和'$'，默认为'%'
                handlers | Python 3.3中新添加的配置项。该选项如果被指定，它应该是一个创建了多个Handler的可迭代对象，这些handler将会被添加到root logger。
                需要说明的是：filename、stream和handlers这三个配置项只能有一个存在，不能同时出现2个或3个，否则会引发ValueError异常。
logging模块定义的格式字符串字段
    字段/属性名称 | 使用格式 | 描述
    | - | -
    asctime | %(asctime)s | 日志事件发生的时间--人类可读时间，如：2003-07-08 16:49:45,896
    created | %(created)f | 日志事件发生的时间--时间戳，就是当时调用time.time()函数返回的值
    relativeCreated | %(relativeCreated)d | 日志事件发生的时间相对于logging模块加载时间的相对毫秒数（目前还不知道干嘛用的）
    msecs | %(msecs)d | 日志事件发生事件的毫秒部分
    levelname | %(levelname)s | 该日志记录的文字形式的日志级别（'DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'）
    levelno | %(levelno)s | 该日志记录的数字形式的日志级别（10, 20, 30, 40, 50）
    name | %(name)s | 所使用的日志器名称，默认是'root'，因为默认使用的是 rootLogger
    message | %(message)s | 日志记录的文本内容，通过 msg % args计算得到的
    pathname | %(pathname)s | 调用日志记录函数的源码文件的全路径
    filename | %(filename)s | pathname的文件名部分，包含文件后缀
    module | %(module)s | filename的名称部分，不包含后缀
    lineno | %(lineno)d | 调用日志记录函数的源代码所在的行号
    funcName | %(funcName)s | 调用日志记录函数的函数名
    process | %(process)d | 进程ID
    processName | %(processName)s | 进程名称，Python 3.1新增
    thread | %(thread)d | 线程ID
    threadName | %(thread)s | 线程名称


'''
# logging.basicConfig(level=logging.DEBUG)
#
# logging.debug("This is a debug log.")
# logging.info("This is a info log.")
# logging.warning("This is a warning log.")
# logging.error("This is a error log.")
# logging.critical("This is a critical log.")
# 在配置日志器日志级别的基础上，在配置下日志输出目标文件和日志格式
# LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
# DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p"

# logging.basicConfig(filename='my.log', level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT)
# logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=DATE_FORMAT)

# logging.debug("This is a debug log.")
# logging.info("This is a info log.")
# logging.warning("This is a warning log.")
# logging.error("This is a error log.")
# logging.critical("This is a critical log.")
import logging

logger = logging.getLogger()
logger.setLevel('DEBUG')
BASIC_FORMAT = "%(asctime)s:%(levelname)s:%(message)s"
DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
formatter = logging.Formatter(BASIC_FORMAT, DATE_FORMAT)
chlr = logging.StreamHandler()  # 输出到控制台的handler
chlr.setFormatter(formatter)
# chlr.setLevel('INFO')  # 也可以不设置，不设置就默认用logger的level
fhlr = logging.FileHandler('example.log')  # 输出到文件的handler
fhlr.setFormatter(formatter)
logger.addHandler(chlr)
logger.addHandler(fhlr)
logger.info('this is info')
logger.debug('this is debug')
